#include "mapview.h"
#include "set.h"
#include <wx/dc.h>
#include <wx/dcclient.h>
#include <wx/msgdlg.h>
#include <wx/dcmemory.h>
//(*InternalHeaders(MapView)
#include <wx/intl.h>
#include <wx/string.h>
//*)

//(*IdInit(MapView)
//*)

BEGIN_EVENT_TABLE(MapView,wxPanel)
    //(*EventTable(MapView)
    //*)
    EVT_PAINT(MapView::OnPaint)
    EVT_LEFT_DOWN(MapView::OnLeftDown)
    EVT_LEFT_UP(MapView::OnLeftUp)
    EVT_MOTION(MapView::OnMove)
    EVT_ERASE_BACKGROUND(MapView::OnBackground)
END_EVENT_TABLE()

void MapView::OnBackground(wxEraseEvent &event)
{
    //event.Skip();
}

MapView::MapView(wxWindow* parent,wxWindowID id,const wxPoint& pos,const wxSize& size)
{
    //(*Initialize(MapView)
    Create(parent, id, pos, size, wxTAB_TRAVERSAL, _T("id"));
    //*)
    m_drawSelRect = false;
	m_selRect.SetWidth(0);
	m_selRect.SetHeight(0);
}

MapView::~MapView()
{
    //(*Destroy(MapView)
    //*)
}

void MapView::Draw(wxDC &dc)
{
	if(m_bmp.IsOk())
        dc.DrawBitmap(m_bmp,0,0,true);
	else
		return;
    wxSize gridSize = GetGridSize();
    wxSize size;
	size.SetWidth(m_bmp.GetWidth());
	size.SetHeight(m_bmp.GetHeight());

	/*dc.SetBrush(*wxWHITE_BRUSH);
    dc.SetPen(*wxGREY_PEN);
    dc.DrawRectangle(GetClientSize());*/

    for(int i = 0; i <= size.GetWidth()/gridSize.GetWidth(); i++)
    {
        dc.DrawLine(i*gridSize.GetWidth(),0,i*gridSize.GetWidth(),size.GetHeight());
    }
    for(int i = 0; i <= size.GetHeight()/gridSize.GetHeight(); i++)
    {
        dc.DrawLine(0,i*gridSize.GetHeight(),size.GetWidth(),i*gridSize.GetHeight());
    }
	//dc.SetLogicalFunction(wxINVERT);
    dc.SetBrush(*wxTRANSPARENT_BRUSH );
	wxBitmap obs(m_obstructImg);
	wxBitmap shelter(m_shelterImg);

    for(int i = 0; i < size.GetHeight()/gridSize.GetHeight(); i++)
    {
        for(int j = 0; j < size.GetWidth()/gridSize.GetWidth();j++)
        {
            if((m_obstruct.size() > (size_t)i) && (m_obstruct[i].size() > (size_t)j) && m_obstruct[i].test(j))
            {
                //dc.DrawRectangle(j*gridSize.GetWidth(),i*gridSize.GetHeight(),gridSize.GetWidth(),gridSize.GetHeight());
				dc.DrawBitmap(obs,j*gridSize.GetWidth(),i*gridSize.GetHeight(),true);
            }
        }
    }

	for(int i = 0; i < size.GetHeight()/gridSize.GetHeight(); i++)
    {
        for(int j = 0; j < size.GetWidth()/gridSize.GetWidth();j++)
        {
            if((m_shelter.size() > (size_t)i) && (m_shelter[i].size() > (size_t)j) && m_shelter[i].test(j))
            {
                //dc.DrawRectangle(j*gridSize.GetWidth(),i*gridSize.GetHeight(),gridSize.GetWidth(),gridSize.GetHeight());
				dc.DrawBitmap(shelter,j*gridSize.GetWidth(),i*gridSize.GetHeight(),true);
            }
        }
    }
}
void MapView::OnPaint(wxPaintEvent& event)
{
    wxPaintDC dc(this);
	DoPrepareDC(dc);

    wxSize clientSize = GetSize();
    wxBitmap bmp(clientSize.GetWidth(),clientSize.GetHeight());
    wxMemoryDC memDC(bmp);
    Draw(memDC);
    //dc.DrawBitmap(bmp,0,0);
    dc.Blit(0,0,clientSize.GetWidth(),clientSize.GetHeight(),&memDC,0,0);
}

void MapView::OnLeftDown(wxMouseEvent &event)
{
	event.Skip();
    int x = event.GetX();
    int y = event.GetY();
	CalcUnscrolledPosition(event.GetX(),event.GetY(),&x,&y);
    wxSize size = GetGridSize();
    m_selRect.SetX(x/size.GetWidth()*size.GetWidth());
    m_selRect.SetY(y/size.GetHeight()*size.GetHeight());
    m_selRect.SetWidth(10);
    m_selRect.SetHeight(10);
    m_drawSelRect = true;
}

void MapView::ChangeObstruct(wxRect &rect,bool add)
{
    wxSize size = GetSize();
    wxSize gridSize = GetGridSize();
    
    int num = size.GetWidth()/gridSize.GetWidth();
	int maxH = size.GetHeight()/gridSize.GetHeight();
    for(int i = 0; i < maxH; i++)
    {
        if(m_obstruct[i].size() < (size_t)num)
            m_obstruct[i].resize(num);
        if((i >= rect.GetY()/gridSize.GetWidth()) && (i <= rect.GetBottom()/gridSize.GetHeight()))
        {
            for(int j = rect.GetX()/gridSize.GetWidth(); j <= rect.GetRight()/gridSize.GetWidth();j++)
            {
				if(j < num)
					m_obstruct[i].set(j,add);
            }
        }
    }
}

void MapView::ChangeShelter(wxRect &rect,bool add)
{
	wxSize size = GetSize();
    wxSize gridSize = GetGridSize();
    
    int num = size.GetWidth()/gridSize.GetWidth();
	int maxH = size.GetHeight()/gridSize.GetHeight();
    for(int i = 0; i < maxH; i++)
    {
        if(m_shelter[i].size() < (size_t)num)
            m_shelter[i].resize(num);
        if((i >= rect.GetY()/gridSize.GetWidth()) && (i <= rect.GetBottom()/gridSize.GetHeight()))
        {
            for(int j = rect.GetX()/gridSize.GetWidth(); j <= rect.GetRight()/gridSize.GetWidth();j++)
            {
				if(j < num)
					m_shelter[i].set(j,add);
            }
        }
    }
}

void MapView::OnLeftUp(wxMouseEvent &event)
{
    m_drawSelRect = false;
	if(m_selRect.GetWidth() > 0 && m_selRect.GetHeight() > 0)
	{
		if(GetCheckType() == ECTCanWalk)
			ChangeObstruct(m_selRect,false);
		else if(GetCheckType() == ECTCanNotWalk)
			ChangeObstruct(m_selRect,true);
		else if(GetCheckType() == ECTShelter)
			ChangeShelter(m_selRect,true);
		else if(GetCheckType() == ECTNoShelter)
			ChangeShelter(m_selRect,false);
	}
    Refresh();
}

void MapView::OnActive(wxShowEvent &event)
{
    if(!event.IsShown())
        return;
    wxMessageBox("active");
}

void MapView::SetImage(wxString &fileName)
{
	m_bmp.LoadFile(fileName,wxBITMAP_TYPE_JPEG);
	wxSize gridSize = GetGridSize();
	int w = gridSize.GetWidth();
	int h = gridSize.GetHeight();
	unsigned char *obs = new unsigned char[3*w*h];
	unsigned char *shel = new unsigned char[3*w*h];
	unsigned char *obsAlpha = new unsigned char[w*h];
	unsigned char *shelAlpha = new unsigned char[w*h];
	for(int i = 0; i < w*h; i++)
	{
		obs[3*i] = 0xff;
		obs[3*i+1] = 0;
		obs[3*i+2] = 0xff;
		shel[3*i] = 0xff;
		shel[3*i+1] = 0;
		shel[3*i+2] = 0;
		obsAlpha[i] = 150;
		shelAlpha[i] = 150;
	}
	m_obstructImg.Create(w,h,obs,obsAlpha);
	m_shelterImg.Create(w,h,shel,shelAlpha);

	wxSize size = GetSize();
	m_obstruct.resize(size.GetHeight()/gridSize.GetHeight());
	m_shelter.resize(size.GetHeight()/gridSize.GetHeight());

	for(size_t i = 0; i < m_obstruct.size(); i++)
	{
		m_obstruct[i].clear();
	}
	for(size_t i = 0; i < m_shelter.size(); i++)
	{
		m_shelter[i].clear();
	}

	SetVirtualSize(m_bmp.GetWidth(),m_bmp.GetHeight());
	SetScrollRate( 10, 10);
	Refresh();
}
wxSize MapView::GetSize()
{
	wxSize size = GetClientSize();
	if(m_bmp.IsOk())
	{
		wxSize gridSize = GetGridSize();
		if(size.GetWidth() < m_bmp.GetWidth())
			size.SetWidth(m_bmp.GetWidth());
		if(size.GetHeight() < m_bmp.GetHeight())
			size.SetHeight(m_bmp.GetHeight());
	}
	return size;
}
void MapView::OnMove(wxMouseEvent &event)
{
    if(!m_drawSelRect)
        return;

    int x,y;
    CalcUnscrolledPosition(event.GetX(),event.GetY(),&x,&y);

    wxSize clientSize = GetSize();
    if(x > clientSize.GetWidth())
        x = clientSize.GetWidth();
    if(y > clientSize.GetHeight())
        y = clientSize.GetHeight();

    if((x < m_selRect.GetX()) || (y < m_selRect.GetY()))
        return;

    wxSize size = GetGridSize();
    /*bool modx = x%size.GetWidth() > 0;
    if(modx)
        x = (x/size.GetWidth()+1)*size.GetWidth();
    else
        x = x/size.GetWidth()*size.GetWidth();
    bool mody = y%size.GetHeight() > 0;
    if(mody)
        y = (y/size.GetHeight()+1)*size.GetHeight();
    else
        y = y/size.GetHeight()*size.GetHeight();*/
    int w,h;
    w = x - m_selRect.GetX();
    h = y - m_selRect.GetY();
    m_selRect.SetX(std::min(x,m_selRect.GetX()));
    m_selRect.SetY(std::min(y,m_selRect.GetY()));
    m_selRect.SetWidth(w);
    m_selRect.SetHeight(h);

    wxClientDC dc(this);
    DoPrepareDC(dc);
	wxBitmap bmp(clientSize.GetWidth(),clientSize.GetHeight());
    wxMemoryDC memDC(bmp);
    Draw(memDC);
    memDC.SetBrush(*wxTRANSPARENT_BRUSH);
    memDC.SetPen(*wxRED_PEN);
    memDC.DrawRectangle(m_selRect);

    dc.Blit(0,0,clientSize.GetWidth(),clientSize.GetHeight(),&memDC,0,0);
}

